/*
* file: mqttsn.h
* author:   vincent.cws2008@gmail.com
* history:
* @2019-04-29: initial - circle_buf
*
*/


#include "stdio.h"
#include "stdarg.h"
#include "LoopObj.h"
#ifndef NULL
#define NULL 0
#endif

#include "stdlib.h"

#include "project_config.h"

#define LCD_PSRAM 0
#if LCD_PSRAM
static struct HeapCB *heap=0;
static void *myx_malloc (size_t size)
{

    if (heap==0){
        heap =Heap_FindHeap("PSRAM");
        if(heap==NULL){
            printf("M_FindHeapd  ERROR!\r\n");
            return NULL;
        }
    }
    return M_MallocHeap(size,heap,0);
}

static void myx_free (void *p)
{
    return M_FreeHeap(p, heap);
}

#define malloc     myx_malloc
#define free myx_free
#endif

enum {
    LOOP_MODE_CUTOVER = 0,
    LOOP_MODE_BLOCKED,
    LOOP_MODE_MOVESTEP,
};


typedef struct StLoopObjMgr {

    int total_cnts;
    int size_type;
    int used_cnts;
    int mode; //mode==0: full will over write;;
                //mode==1: full will stop, and push return failed
                //mode==2: full will pull one and push one,keep the latest full data.
    int idx_head;
    int idx_tail;
    unsigned char arrRec[0];
}StLoopObjMgr;

typedef void(*FunPrint)(void *data);

static inline struct StLoopObjMgr* CreateLoopObjMgr(int sizeOfType, int cntsOfArr, int mode)
{
    int size = sizeof(struct StLoopObjMgr) + sizeOfType * cntsOfArr;
    struct StLoopObjMgr *pMgr = (struct StLoopObjMgr*)malloc(size);
    if (pMgr == 0) return 0;
    memset(pMgr, 0, size);
    pMgr->mode = mode;
    pMgr->used_cnts = 0;
    pMgr->size_type = sizeOfType;
    pMgr->total_cnts = cntsOfArr;

    return pMgr;
}

static inline void DeleteLoopObjMgr(struct StLoopObjMgr *pMgr)
{
    if (pMgr) free(pMgr);
}

static inline int PushLoopObjTail(struct StLoopObjMgr* pMgr, void *pRecObj)
{
    int ret = 0;

    if (pMgr->idx_tail == pMgr->idx_head && pMgr->used_cnts != 0) {
        if (pMgr->mode == 1) {
            //printf("warning: the queue full, return -1!\r\n");
            ret = -1;
            goto END_FUN;
        }
        else if (pMgr->mode == 2) {
            pMgr->used_cnts--;
            pMgr->idx_head++;
            pMgr->idx_head = pMgr->idx_head % pMgr->total_cnts;
            printf("warning: recover the queue, but pull one first, and push one later!\r\n");
        }
        else { // if (pMgr->mode == 0)
            pMgr->used_cnts = 0;
            printf("warning: recover the queue!\r\n");
        }
    }
    if (pMgr->size_type == 1){
        pMgr->arrRec[pMgr->idx_tail]=*(unsigned char*)pRecObj;
    }
    else {
        memcpy(&pMgr->arrRec[pMgr->idx_tail * pMgr->size_type], pRecObj, pMgr->size_type);
    }
    pMgr->used_cnts++;
    pMgr->idx_tail++;
    pMgr->idx_tail = pMgr->idx_tail % pMgr->total_cnts;
END_FUN:

    return ret;
}

static inline int  PullLoopObjHead(struct StLoopObjMgr* pMgr, void *pRecObj)
{
    int ret = 0;

    if (pMgr->idx_head == pMgr->idx_tail && pMgr->used_cnts == 0) {
        //printf("warning: the queue empty, return -1!\r\n");
        ret = -1;
        goto END_FUN;
    }
    if (pMgr->size_type == 1){
        *(unsigned char*)pRecObj = pMgr->arrRec[pMgr->idx_head];
    }
    else {
        memcpy(pRecObj, &pMgr->arrRec[pMgr->idx_head * pMgr->size_type], pMgr->size_type);
    }
    pMgr->used_cnts--;
    pMgr->idx_head++;
    pMgr->idx_head = pMgr->idx_head % pMgr->total_cnts;

END_FUN:

    return ret;
}

static inline int  PeekPullLoopObjHead(struct StLoopObjMgr* pMgr, void *pRecObj, int n)
{
    int head = pMgr->idx_head;
    int tail = pMgr->idx_tail;
    int cnts = pMgr->used_cnts;
    if (n < 0) return -1;

    cnts = cnts > n ? n : cnts;

    while (cnts) {
        if (pMgr->size_type == 1){
            *(unsigned char*)pRecObj = pMgr->arrRec[head];
        }
        else {
            memcpy(pRecObj, &pMgr->arrRec[head * pMgr->size_type], pMgr->size_type);
        }
        head++;
        head = head % pMgr->total_cnts;
        cnts = cnts-1;
    }
    return cnts;
}

static inline int  ResetLoopObj(struct StLoopObjMgr* pMgr)
{
    pMgr->used_cnts = pMgr->idx_head = pMgr->idx_tail = 0;
    return 0;
}


static inline int PrintLoopObj(struct StLoopObjMgr* pMgr, FunPrint f)
{
    printf("PrintLoopRec: total_cnts=%d, used_cnts=%d, size_type=%d, idx_head=%d, idx_tail=%d!\r\n", pMgr->total_cnts, pMgr->used_cnts, pMgr->size_type, pMgr->idx_head, pMgr->idx_tail);
    int cnts = pMgr->used_cnts;
    int i = pMgr->idx_head;
    while (cnts) {
        f(&pMgr->arrRec[i * pMgr->size_type]);
        cnts--;
        i++;
        i = i % pMgr->total_cnts;
    }
    printf("\r\n");
}

#if 0
#define FRM_REC_QUE_MAX 3
typedef struct StFrmRec {
    int frm_length;
    int frm_duration;//ms
}StRecFrmInfo;

static inline void FrmRecPrint(void *data)
{
    struct StFrmRec *pFrmRec = (struct StFrmRec*)data;
    printf("{%d,%d} ", pFrmRec->frm_length, pFrmRec->frm_duration);
}

static inline int FrmRecTest()
{
    struct StFrmRec data[30] = { { 1,2 },{ 3,4 },{ 5,6 },{ 7,8 },{ 9,10 },{ 1,2 },{ 3,4 },{ 5,6 },{ 7,8 },{ 9,10 },{ 1,2 },{ 3,4 },{ 5,6 },{ 7,8 },{ 9,10 } };

    struct StFrmRec temp;

    struct StLoopObjMgr* pMgr = CreateLoopObjMgr(sizeof(struct StFrmRec), FRM_REC_QUE_MAX, 2);
    for (int i = 0; i < 5; i++)
    {
        PushLoopObjTail(pMgr, &data[i]);
        PrintLoopObj(pMgr, FrmRecPrint);
    }
    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);;

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);

    PushLoopObjTail(pMgr, &data[0]);
    PrintLoopObj(pMgr, FrmRecPrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, FrmRecPrint);

    DeleteLoopObjMgr(pMgr);

    return 0;
}


#define BYTE_QUE_MAX 3

static inline void BytePrint(void *data)
{
    char *pFrmRec = (char*)data;
    printf("{%c} ", *pFrmRec);
}

static inline int test()
{
    char data[30] = "abcdefghijklmnopqrstuvwxyz";

    char temp;

    struct StLoopObjMgr* pMgr = CreateLoopObjMgr(sizeof(char), BYTE_QUE_MAX, 0);
    for (int i = 0; i < 5; i++)
    {
        PushLoopObjTail(pMgr, &data[i]);
        PrintLoopObj(pMgr, BytePrint);
    }
    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);;

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);

    PushLoopObjTail(pMgr, &data[0]);
    PrintLoopObj(pMgr, BytePrint);

    PullLoopObjTail(pMgr, &temp);
    PrintLoopObj(pMgr, BytePrint);

    DeleteLoopObjMgr(pMgr);

    return 0;
}
#endif




